package com.leyou.search.service;

import com.leyou.item.pojo.Brand;
import com.leyou.item.pojo.Category;
import com.leyou.item.pojo.SpecParam;
import com.leyou.search.clients.BrandClient;
import com.leyou.search.clients.CategoryClient;
import com.leyou.search.clients.SpecClient;
import com.leyou.search.pojo.Goods;
import com.leyou.search.repository.GoodsRepository;
import com.leyou.search.utils.SearchRequest;
import com.leyou.search.utils.SearchResult;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.Operator;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.LongTerms;
import org.elasticsearch.search.aggregations.bucket.terms.StringTerms;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class SearchService {

    @Autowired
    private GoodsRepository goodsRepository;

    @Autowired
    private BrandClient brandClient;

    @Autowired
    private CategoryClient categoryClient;

    @Autowired
    private SpecClient specClient;

    public SearchResult page(SearchRequest searchRequest) {
        //自定义查询
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        //查询条件，如果没有查询条件，就不应该开始查询
        String key = searchRequest.getKey();

        if (!StringUtils.isNotBlank(key)) {
            return null;
        }
        //调用构建方法，返回一个bool的查询条件对象
        QueryBuilder query = buildBasicQueryWithFilter(searchRequest);
        //添加查询条件
        queryBuilder.withQuery(query);

        //spring Data 中所有的分页都是从零开始的
        queryBuilder.withPageable(PageRequest.of(searchRequest.getPage() - 1, searchRequest.getSize()));

        // 1.3、聚合
        String categoryAggName = "category"; // 商品分类聚合名称
        String brandAggName = "brand"; // 品牌聚合名称
        queryBuilder.addAggregation(AggregationBuilders.terms(categoryAggName).field("cid3"));
        queryBuilder.addAggregation(AggregationBuilders.terms(brandAggName).field("brandId"));


        List<Category> categories = new ArrayList<>();
        List<Brand> brands = new ArrayList<>();

        //对商品的分类和品牌进行聚合


        //执行查询
        AggregatedPage<Goods> goodsPage = (AggregatedPage<Goods>) goodsRepository.search(queryBuilder.build());
        LongTerms categoryTerms = (LongTerms) goodsPage.getAggregation(categoryAggName);
        List<Long> cids = new ArrayList<>();
        List<LongTerms.Bucket> buckets = categoryTerms.getBuckets();
        //从分类的聚合分桶中获取所有的分类id信息
        buckets.forEach(bucket -> cids.add(bucket.getKeyAsNumber().longValue()));

        //根据分类的id查询分类的名称
        List<String> names = categoryClient.queryNameByIds(cids);
        //自行组合对象
        for (int i = 0; i < cids.size(); i++) {
            Category category = new Category();
            category.setId(cids.get(i));
            category.setName(names.get(i));
            categories.add(category);
        }
        List<Long> brandIds = new ArrayList<>();
        LongTerms brandTerms = (LongTerms) goodsPage.getAggregation(brandAggName);
        //从品牌的聚合分桶中获取所有的品牌id信息
        brandTerms.getBuckets().forEach(bucket -> brandIds.add(bucket.getKeyAsNumber().longValue()));

        //需要把品牌的id集合以及分类的id集合转换成对象集合

        brandIds.forEach(brandId -> {
            Brand brand = brandClient.queryBrandById(brandId);
            brands.add(brand);
        });


        //把查询结果返回

        List<Map<String, Object>> specs = null;

        //只有分类唯一才展示规格参数
        if (categories.size() == 1) {
            //获取规格参数，根据分类id
            specs = getSpecs(categories.get(0).getId(),query);
        }
        return new SearchResult(goodsPage.getTotalElements(), new Long(goodsPage.getTotalPages()), goodsPage.getContent(), categories, brands, specs);
    }

    /**
     *  对查询到的数据进行可搜索规格参数的聚合条件，聚合是要和搜索条件相关，搜索到什么内容，就聚合什么，不要全部聚合
     * @param id
     * @return
     */
    private List<Map<String, Object>> getSpecs(Long id,QueryBuilder query) {
        List<Map<String, Object>> specList = new ArrayList<>();


        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();

        //先根据查询条件，执行查询
        queryBuilder.withQuery(query);
        //对规格参数进行聚合，聚合要拿到所有的可搜索的规格参数
        List<SpecParam> searchingSpecParams = specClient.querySpecParam(null, id, true,null);
        //添加聚合条件 聚合的名称就是可搜索规格参数的名称
        searchingSpecParams.forEach(specParam -> queryBuilder.addAggregation(AggregationBuilders.terms(specParam.getName()).field("specs." + specParam.getName() + ".keyword")));
        AggregatedPage<Goods> page = (AggregatedPage<Goods>) goodsRepository.search(queryBuilder.build());
        searchingSpecParams.forEach(specParam -> {
            //可搜索规格参数的名称
            String name = specParam.getName();
            //根据聚合名称获取结果
            StringTerms stringTerms = (StringTerms) page.getAggregation(name);
            List<String> values = new ArrayList<>();

            List<StringTerms.Bucket> buckets = stringTerms.getBuckets();
            //把聚合分桶中每个值存入values集合中

            buckets.forEach(bucket -> values.add(bucket.getKeyAsString()));

            Map<String, Object> specMap = new HashMap<>();
            specMap.put("k", name);
            specMap.put("options", values);
            specList.add(specMap);

        });

        return specList;
    }

    // 构建基本查询条件
    private QueryBuilder buildBasicQueryWithFilter(SearchRequest request) {
        //创建基本布尔查询
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        // 基本查询条件
        queryBuilder.must(QueryBuilders.matchQuery("all", request.getKey()).operator(Operator.AND));
        // 过滤条件构建器
        BoolQueryBuilder filterQueryBuilder = QueryBuilders.boolQuery();
        // 整理过滤条件
        Map<String, String> filter = request.getFilter();
        for (Map.Entry<String, String> entry : filter.entrySet()) {
            String key = entry.getKey();
            String value = entry.getValue();
            // 商品分类和品牌可以直接查询不需要拼接
            if (key != "cid3" && key != "brandId") {
                key = "specs." + key + ".keyword";
            }
            // 字符串类型，进行term查询
            filterQueryBuilder.must(QueryBuilders.termQuery(key, value));
        }
        // 添加过滤条件
        queryBuilder.filter(filterQueryBuilder);
        return queryBuilder;
    }
}
